package com.ruoyi.quartz.task;

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.calculationSalary.service.CalculationSalaryService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.compensationManagement.domain.CompensationDeductionAmountSettings;
import com.ruoyi.compensationManagement.domain.CompensationSalarySetting;
import com.ruoyi.compensationManagement.domain.CompensationStaffpayroll;
import com.ruoyi.compensationManagement.domain.PositionSettings;
import com.ruoyi.compensationManagement.service.ICompensationDeductionAmountSettingsService;
import com.ruoyi.compensationManagement.service.ICompensationSalarySettingService;
import com.ruoyi.compensationManagement.service.ICompensationStaffpayrollService;
import com.ruoyi.compensationManagement.service.IPositionSettingsService;
import com.ruoyi.compensationManagement.service.impl.CompensationRetirespayrollServiceImpl;
import com.ruoyi.core.service.AttendanceCalculationService;
import com.ruoyi.system.domain.SysUserPositionLevelHistory;
import com.ruoyi.system.domain.SysUserSalaryHistory;
import com.ruoyi.system.service.ISysUserPositionLevelHistoryService;
import com.ruoyi.system.domain.SysUserPosition;
import com.ruoyi.system.mapper.SysUserPositionLevelMapper;
import com.ruoyi.system.service.ISysCommonService;
import com.ruoyi.system.service.ISysUserSalaryHistoryService;
import com.ruoyi.system.service.ISysUserService;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 工资表定时任务
 *
 * @author zy
 */
@Component("payrollTasks")
public class payrollTasksRegular {
    @Autowired
    private ICompensationStaffpayrollService compensationStaffpayrollService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysCommonService sysCommonService;

    @Autowired
    private CalculationSalaryService calculationSalaryService;

    @Autowired
    private ICompensationDeductionAmountSettingsService compensationDeductionAmountSettingsService;

    @Autowired
    private ISysUserPositionLevelHistoryService sysUserPositionLevelHistoryService;

    @Autowired
    private IPositionSettingsService positionSettingsService;

    @Autowired
    private ISysUserSalaryHistoryService sysUserSalaryHistoryService;

    @Autowired
    private ICompensationSalarySettingService compensationSalarySettingService;

    @Autowired
    private AttendanceCalculationService attendanceCalculationService;

    @Autowired
    private SysUserPositionLevelMapper sysUserPositionLevelMapper;

    private static final Logger log = LoggerFactory.getLogger(payrollTasksRegular.class);

    //生成每月工资表
    public String generateMonthlyPayroll(String nowDateStr) throws ParseException {
        Date nowDate = DateUtils.parseDate(nowDateStr, "yyyy-MM");
        Date date = new Date();
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        List<SysUser> userList = sysUserService.selectAllUserList();
        int totalNum = userList.size();
        try {
            for (SysUser user : userList) {
                if (StringUtils.isNull(user.getEntryTime())) {
                    continue;
                }
                if (user.getEntryTime().after(date)) {
                    continue;
                }
                if (user.getEmployeeStatus().equals("退休") || user.getEmployeeStatus().equals("离职")) {
                    continue;
                }
                //非停用或者删除
                if (user.getUserId() != 1 && user.getStatus().equals("0") && user.getDelFlag().equals("0")) {
                    //未设置薪级
                    if (user.getSalaryScale() == null) {
                        failureNum++;
                        failureMsg.append("<br/>" + "【错误】" + "当前工号为：" + user.getJobNumber() + ",姓名：" + user.getNickName() + "的员工工资生成错误。原因：未设置薪级");
                        continue;
                    }
                    //未设置岗位等级
                    if (sysUserPositionLevelMapper.getPositionIdByUserId(user.getUserId()) == 0) {
                        failureNum++;
                        failureMsg.append("<br/>" + "【错误】" + "当前工号为：" + user.getJobNumber() + ",姓名：" + user.getNickName() + "的员工工资生成错误。原因：未设置岗位等级");
                        continue;
                    }
                    //未设置员工类型
                    if (user.getEmployeeType() == null || user.getEmployeeType().equals("")) {
                        failureNum++;
                        failureMsg.append("<br/>" + "【错误】" + "当前工号为：" + user.getJobNumber() + ",姓名：" + user.getNickName() + "的员工工资生成错误。原因：未设置员工类型");
                        continue;
                    }
                    /*将数据存入工资表对象 计算工资存储进数据库*/
                    CompensationStaffpayroll compensationStaffpayroll = new CompensationStaffpayroll();
                    //设置工号、姓名、员工状态、员工政治面貌、部门id、薪资时间
                    compensationStaffpayroll.setJobnumber(user.getJobNumber());
                    compensationStaffpayroll.setNickName(user.getNickName());
                    compensationStaffpayroll.setEmployeeType(user.getEmployeeType());
                    compensationStaffpayroll.setSalaryyearmonth(nowDate);
                    //获取传入月份时的历史岗位信息对象
                    SysUserPositionLevelHistory sysUserPosition = sysUserPositionLevelHistoryService.getPositionsByUserIdAndNowDate(user.getUserId(), nowDate);
                    /*用历史岗位等级id获取传入日期时的岗位薪级信息*/
                    PositionSettings positionSet = positionSettingsService.selectPositionSettingsByPositionId(sysUserPosition.getPositionId());

                    //获取传入月份时的薪级等级id
                    SysUserSalaryHistory userSalaryHistory = sysUserSalaryHistoryService.getSalaryHistoryByUserIdAndNowDate(user.getUserId(), nowDate);
                    /*根据薪级历史表获取传入日期时的薪级对象*/
                    CompensationSalarySetting compensationSalary = compensationSalarySettingService.selectCompensationSalarySettingByPayId(userSalaryHistory.getPayId());

                    //薪级名称
                    compensationStaffpayroll.setSalary(compensationSalary.getPayLevel());
                    //岗位名称
                    compensationStaffpayroll.setPosition(sysCommonService.getUserPositionByUserId(user.getUserId()));

                    //应发工资
                    BigDecimal wagesPayable = new BigDecimal("0");

                    //薪级工资
                    compensationStaffpayroll.setPayWages(compensationSalary.getPayWages());
                    wagesPayable = wagesPayable.add(compensationStaffpayroll.getPayWages());

                    //岗位工资
                    compensationStaffpayroll.setPositionSalary(positionSet.getPositionSalary());
                    wagesPayable = wagesPayable.add(compensationStaffpayroll.getPositionSalary());

                    //基础性绩效工资
                    compensationStaffpayroll.setBasicPerformancePay(positionSet.getBasicPerformancePay());
                    wagesPayable = wagesPayable.add(compensationStaffpayroll.getBasicPerformancePay());

                    //奖励性绩效工资
                    compensationStaffpayroll.setIncentivizedPerformancePay(positionSet.getIncentivizedPerformancePay());
                    wagesPayable = wagesPayable.add(compensationStaffpayroll.getIncentivizedPerformancePay());

                    //基础性绩效奖
                    compensationStaffpayroll.setBasicPerformanceAward(positionSet.getBasicPerformanceAward());
                    wagesPayable = wagesPayable.add(compensationStaffpayroll.getBasicPerformanceAward());

                    //加班费
                    compensationStaffpayroll.setOvertimePay(calculateOvertimePay(calculationSalaryService.workOvertime(user.getUserId(), nowDate)));
                    wagesPayable = wagesPayable.add(compensationStaffpayroll.getOvertimePay());

                    //应发工资
                    compensationStaffpayroll.setWagesPayable(wagesPayable);

                    /*=========================扣款部分========================*/
                    //实扣数
                    BigDecimal actualDeduction = new BigDecimal("0");

                    //遍历循环扣款金额设置表
                    CompensationDeductionAmountSettings compensationDeductionAmountSettings = new CompensationDeductionAmountSettings();
                    if (user.getEmployeeType().equals("在编人员")){
                        compensationDeductionAmountSettings.setZbExecute("1");
                    }
                    if (user.getEmployeeType().equals("聘用人员")){
                        compensationDeductionAmountSettings.setPyExecute("1");
                    }
                    List<CompensationDeductionAmountSettings> listDeductionAmountSettings = compensationDeductionAmountSettingsService.selectCompensationDeductionAmountSettingsList(compensationDeductionAmountSettings);

                    //哺乳假扣款
                    BigDecimal lactationLeave = new BigDecimal("0");
                    if (attendanceCalculationService.getBreastFeedingLeaveHourForMonth(user.getUserId(), DateUtils.parseDateToStr("yyyy-MM", nowDate)) > 0) {
                        lactationLeave = calculateLessen(calculationSalaryService.lactationLeave(user.getUserId(), nowDate));
                    }
                    actualDeduction = actualDeduction.add(lactationLeave);
                    //事假扣款
                    BigDecimal compassionateLeave = new BigDecimal(String.valueOf(calculateLessen(calculationSalaryService.compassionateLeave(user.getUserId(), nowDate))));
                    actualDeduction = actualDeduction.add(compassionateLeave);
                    //病假扣款
                    BigDecimal sickLeave = new BigDecimal(String.valueOf(calculateLessen(calculationSalaryService.sickLeave(user.getUserId(), nowDate))));
                    actualDeduction = actualDeduction.add(sickLeave);

                    //循环浮动项分别计算费用和比率
                    for (CompensationDeductionAmountSettings listDeductionAmountSetting : listDeductionAmountSettings) {
                        //是比率用应发工资*比率
                        if (listDeductionAmountSetting.getIsRate().equals("Y")) {
                            BigDecimal bigDecimal = new BigDecimal("0");
                            BigDecimal rateM = new BigDecimal("0.01");
                            BigDecimal rate = listDeductionAmountSetting.getRate();
                            rate = rate.multiply(rateM);
                            bigDecimal = bigDecimal.add(wagesPayable.multiply(rate));
                            //四舍五入
                            bigDecimal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
                            //加进实扣数
                            actualDeduction = actualDeduction.add(bigDecimal);
                            //把数据放回json方便读写
                            listDeductionAmountSetting.setCost(bigDecimal);
                        }
                        //是费用直接加进实扣数
                        else if (listDeductionAmountSetting.getIsRate().equals("N")) {
                            BigDecimal bigDecimal = new BigDecimal("0");
                            bigDecimal = bigDecimal.add(listDeductionAmountSetting.getCost());
                            //四舍五入
                            bigDecimal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP);
                            //加进实扣数
                            actualDeduction = actualDeduction.add(bigDecimal);

                            //将 哺乳假扣款\事假扣款\病假扣款 存入cost
                            if (listDeductionAmountSetting.getDeductionsType().equals("扣哺乳假工资")) {
                                listDeductionAmountSetting.setCost(lactationLeave);
                            } else if (listDeductionAmountSetting.getDeductionsType().equals("扣事假工资")) {
                                listDeductionAmountSetting.setCost(compassionateLeave);
                            } else if (listDeductionAmountSetting.getDeductionsType().equals("扣病假工资")) {
                                listDeductionAmountSetting.setCost(sickLeave);
                            }
                        }
                    }


                    //实扣数
                    compensationStaffpayroll.setActualDeduction(actualDeduction);

                    //实发数=应发工资-实扣数
                    compensationStaffpayroll.setActualSalary(wagesPayable.subtract(actualDeduction));

                    //将浮动项目数组对象转换为字符串存储数据库
                    compensationStaffpayroll.setDeductionsPart(JSON.toJSONString(listDeductionAmountSettings));

                    //插入数据库
                    compensationStaffpayrollService.insertCompensationStaffpayroll(compensationStaffpayroll);
                    successNum++;
                    successMsg.append("<br/>" + "数据：" + successNum + "当前工号为：" + user.getJobNumber() + ",姓名：" + user.getNickName() + "的员工工资生成成功");
                }
            }
        } catch (Exception e) {
            failureNum++;
            String msg = "<br/>" + "生成失败";
            log.error(msg, e);
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "部分导入失败，本次应生成" + totalNum + "条工资数据,其中" + successNum + "条生成成功" + ",共 " + failureNum + "生成失败，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您" + nowDateStr + "工资生成成功，总共生成" + totalNum + "条工资数据" + "数据如下：");
        }
        return successMsg.toString();
    }

    //计算workOvertime加班费
    public BigDecimal calculateOvertimePay(Map<String, String> OvertimePay) {
        BigDecimal sum = new BigDecimal("0");
        //拿map里所有工资
        if (StringUtils.isNotEmpty(OvertimePay)) {
            BigDecimal a = new BigDecimal(OvertimePay.get("workOvertime_base_pay"));
            BigDecimal b = new BigDecimal(OvertimePay.get("workOvertime_base_performance_pay"));
            BigDecimal c = new BigDecimal(OvertimePay.get("workOvertime_incentive_performance_pay"));
            //四舍五入
            a = a.setScale(2, BigDecimal.ROUND_HALF_UP);
            b = b.setScale(2, BigDecimal.ROUND_HALF_UP);
            c = c.setScale(2, BigDecimal.ROUND_HALF_UP);

            sum = sum.add(a);
            sum = sum.add(b);
            sum = sum.add(c);
        }
        return sum;
    }

    //计算lessen:哺乳假\事假\病假
    public BigDecimal calculateLessen(Map<String, String> lessen) {
        BigDecimal sum = new BigDecimal("0");
        //拿map里所有工资
        if (StringUtils.isNotEmpty(lessen)) {
            BigDecimal a = new BigDecimal(lessen.get("lessen_base_pay"));
            BigDecimal b = new BigDecimal(lessen.get("lessen_base_performance_pay"));
            BigDecimal c = new BigDecimal(lessen.get("lessen_incentive_performance_pay"));
            //四舍五入
            a = a.setScale(2, BigDecimal.ROUND_HALF_UP);
            b = b.setScale(2, BigDecimal.ROUND_HALF_UP);
            c = c.setScale(2, BigDecimal.ROUND_HALF_UP);

            sum = sum.add(a);
            sum = sum.add(b);
            sum = sum.add(c);
        }
        return sum;
    }
}
